#include "sk6812_spi.h"
#include <math.h>

// 灯条显存SPI数据缓存
uint8_t gWs2812bDat_SPI[WS2812B_AMOUNT * 24] = {0};
// 灯条显存
tWs2812bCache_TypeDef gWs2812bDat[WS2812B_AMOUNT] = {
    0x00, 0x00, 0x00, // 黑色
    0xFF, 0x00, 0x00, // 红色
    0xFF, 0x80, 0x00, // 橙色
    0xFF, 0xFF, 0x00, // 黄色
    0x80, 0xFF, 0x00, // 黄绿色
    0x00, 0xFF, 0x00, // 绿色
    0x00, 0xFF, 0x80, // 青绿色
    0x00, 0xFF, 0xFF, // 青色
    0x00, 0x80, 0xFF, // 天蓝色
    0x00, 0x00, 0xFF, // 蓝色
    0x80, 0x00, 0xFF, // 蓝紫色
    0xFF, 0x00, 0xFF, // 紫色
    0xFF, 0x00, 0x80, // 紫红色
    0x80, 0x80, 0x80, // 灰色
    0xFF, 0xFF, 0xFF // 白色

};
#define WAVE_SPEED 50  // 波浪移动速度(ms)
#define WAVE_LENGTH 24 // 波浪长度
#define DARK_LEDS 6    // 熄灭的LED数量
// 灯效状态机全局变量
static uint16_t wave_offset = 0;      // 记录当前波浪的偏移量（用于控制波浪位置）
static uint32_t last_update_time = 0; // 记录上一次更新波浪位置的时间（毫秒）
static uint8_t rainbow_phase = 0;     // 彩虹渐变相位
static uint8_t uniform_phase = 0;     // 统一渐变相位
static uint8_t comet_position = 0;    // 彗星位置
static uint8_t stack_height = 0;      // 堆积高度
static uint32_t effect_last_time = 0; // 灯效上次更新时间
// 外部变量声明：
extern uint8_t current_speed_level; // current_speed_level - 当前速度等级（0-4），控制波浪移动速度
extern const uint16_t speed_delays[5]; // speed_delays[5]     - 不同速度等级对应的延迟时间数组（单位：毫秒）

// 将指定LED的RGB颜色值转换为WS2812B协议要求的SPI数据格式，并存储到SPI发送缓冲区中。
void WS2812b_Set(uint16_t Ws2b812b_NUM, uint8_t r, uint8_t g, uint8_t b)
{
    uint8_t *pR = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 8]; // 设置单个不同颜色分量的起始位置。Ws2b812b_NUM是第0颗。
    uint8_t *pG = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24];
    uint8_t *pB = &gWs2812bDat_SPI[(Ws2b812b_NUM) * 24 + 16];

    for (uint8_t i = 0; i < 8; i++)
    {
        if (g & 0x80)
        {
            *pG = CODE_1;
        }
        else
        {
            *pG = CODE_0;
        }
        if (r & 0x80)
        {
            *pR = CODE_1;
        }
        else
        {
            *pR = CODE_0;
        }
        if (b & 0x80)
        {
            *pB = CODE_1;
        }
        else
        {
            *pB = CODE_0;
        }
        r <<= 1;
        g <<= 1;
        b <<= 1;
        pR++;
        pG++;
        pB++;
    }
}
// 更新函数 ，负责将内存中的颜色数据实际发送到LED硬件上显示。
void WS2812B_Task(void)
{
   
    // 将gWs2812bDat数据解析成SPI数据
    for (uint8_t iLED = 0; iLED < WS2812B_AMOUNT; iLED++)
    {
        WS2812b_Set(iLED, gWs2812bDat[iLED].R, gWs2812bDat[iLED].G, gWs2812bDat[iLED].B);
    }
    // 总线输出数据
    HAL_SPI_Transmit(&Spi1Handle, gWs2812bDat_SPI, sizeof(gWs2812bDat_SPI), 0XFFFF);
    uint8_t dat = 0;
    // 使总线输出低电平
    HAL_SPI_Transmit(&Spi1Handle, &dat, 1, 0XFFFF);
    // 帧信号：一个大于50us的低电平
    HAL_Delay(1);
}

/**
 * @brief  重置所有灯效状态
 */
void effect_reset(void)
{
//    rainbow_phase = 0;
//    uniform_phase = 0;
//    comet_position = 0;
//    stack_height = 0;
//    wave_offset = 0;
    effect_last_time = HAL_GetTick();
    last_update_time = HAL_GetTick();
}
// ==================== 非阻塞式灯效函数 ====================
/**
 * @brief  非阻塞彩虹渐变更新
 */
void rainbow_gradient_update(void)
{
    // 获取当前系统时间（毫秒级），用于控制动画更新频率
    uint32_t current_time = HAL_GetTick();

    // 速度控制逻辑：根据当前速度等级的延迟时间决定是否更新动画
    // speed_delays[current_speed_level] 是当前速度对应的延迟时间（单位：毫秒）
    // 如果距离上次更新时间小于设定延迟，不执行更新，直接返回
    if (current_time - effect_last_time < speed_delays[current_speed_level]) {
        return;
    }
    // 更新上次动画更新时间为当前时间
    effect_last_time = current_time;
    // 遍历所有LED灯珠，为每个灯珠设置渐变颜色
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) {
        // 计算每个LED的色相值（Hue）：
        // 1. 基础相位rainbow_phase控制整体彩虹的移动方向
        // 2. (i * 255 / WS2812B_AMOUNT) 使每个灯珠按位置分配不同色相，形成固定渐变
        // 3. 取模255确保色相值在0-254范围内（循环）
        uint8_t hue = (rainbow_phase + (i * 255 / WS2812B_AMOUNT)) % 255;

        // 简化的HSV到RGB颜色转换（仅处理色相Hue，饱和度和亮度固定为最大）
        uint8_t r, g, b; // 红、绿、蓝三色分量
        // 需要红色减弱，绿色增强，色相区间1（0-84）：红色→绿色渐变
        if (hue < 85) {
            r = 255 - hue * 3; // 红色从255逐渐减到0
            g = hue * 3;       // 绿色从0逐渐增到255
            b = 0;             // 蓝色保持0
        } // 需要绿色减弱，蓝色增强，色相区间2（85-169）：绿色→蓝色渐变
        else if (hue < 170) {
            hue -= 85; // 重置区间起点为0
            r = 0;     // 红色保持0
            g = 255 - hue * 3; // 绿色从255逐渐减到0
            b = hue * 3;       // 蓝色从0逐渐增到255
        } // 需要蓝色减弱，红色增强，色相区间3（170-254）：蓝色→红色渐变
        else {
            hue -= 170;
            r = hue * 3;
            g = 0;
            b = 255 - hue * 3;
        }
        // 将计算好的RGB值赋值给当前LED灯珠
        gWs2812bDat[i].R = r;
        gWs2812bDat[i].G = g;
        gWs2812bDat[i].B = b;
    }
    // 将更新后的颜色数据发送到WS2812B灯带，刷新显示彩虹效果
    WS2812B_Task();
    // 更新彩虹相位，使整体效果向右移动（数值越大移动越快）
    rainbow_phase += 5;
    // 当相位超过255时重置为0，确保色相计算循环有效
    if (rainbow_phase >= 255) {
        rainbow_phase = 0;
    }
}

/**
 * @brief  非阻塞统一渐变更新
 */
void uniform_gradient_update(void)
{
    // 获取当前系统时间（毫秒级），用于控制动画更新频率
    uint32_t current_time = HAL_GetTick();

    // 速度控制逻辑：根据当前速度等级的延迟时间决定是否更新颜色
    // 如果距离上次更新的时间小于设定延迟，不执行更新，直接返回
    // 速度等级越高（current_speed_level越大），延迟时间越短，颜色变化越快
    if (current_time - effect_last_time < speed_delays[current_speed_level]) {
        return;
    }
    // 更新上次动画更新时间为当前时间，用于下次延迟判断
    effect_last_time = current_time;

    // 定义RGB三原色分量变量（0-255，0为最暗，255为最亮）
    uint8_t r = 0, g = 0, b = 0;
    // 颜色渐变逻辑：分三个阶段实现红→绿→蓝→红的循环
    // 阶段1：红色逐渐减弱，绿色逐渐增强（红→绿过渡）
    // uniform_phase是统一渐变相位
    if (uniform_phase < 85) {
        r = 255 - uniform_phase * 3; // 红色从255线性减到0（85*3=255）
        g = uniform_phase * 3;       // 红色从255线性减到0（85*3=255）
    } // 阶段2：绿色逐渐减弱，蓝色逐渐增强（绿→蓝过渡）
    else if (uniform_phase < 170) {
        g = 255 - (uniform_phase - 85) * 3; // 绿色从255线性减到0
        b = (uniform_phase - 85) * 3;       // 蓝色从0线性增到255
    } // 阶段3：蓝色逐渐减弱，红色逐渐增强（蓝→红过渡）
    else {
        b = 255 - (uniform_phase - 170) * 3;
        r = (uniform_phase - 170) * 3;
    }
    // 为所有LED灯珠设置相同的颜色（实现"统一"效果）
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) {
        gWs2812bDat[i].R = r;
        gWs2812bDat[i].G = g;
        gWs2812bDat[i].B = b;
    }
    // 将颜色数据发送到WS2812B灯带，刷新显示当前颜色
    WS2812B_Task();
    // 增加相位值，推动颜色进入下一渐变状态（+3控制每次颜色变化的步长）
    uniform_phase += 3;
    // 当相位值超过255时重置为0，实现颜色循环渐变
    if (uniform_phase >= 255) {
        uniform_phase = 0;
    }
}

/**
 * @brief  非阻塞彗星效果更新
 */
void comet_effect_update(void)
{
    // 获取当前系统时间（毫秒级），用于控制动画更新频率
    uint32_t current_time = HAL_GetTick();

    // 根据当前速度等级的延迟时间控制更新频率
    // 如果距离上次更新时间小于设定延迟，则不更新，直接返回
    if (current_time - effect_last_time < speed_delays[current_speed_level]) {
        return;
    }
    // 更新上次更新时间为当前时间
    effect_last_time = current_time;
    
    // 清空所有LED
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 0;
        gWs2812bDat[i].B = 0;
    }
    
    // 绘制彗星头部（白色）
    gWs2812bDat[comet_position].R = 255;
    gWs2812bDat[comet_position].G = 255;
    gWs2812bDat[comet_position].B = 255;

    // 绘制彗星尾巴：创建渐变效果
    // 尾巴长度为10个LED，距离头部越远亮度越低
    for (uint8_t i = 1; i <= 10 && i <= comet_position; i++) {
        uint8_t tail_pos = comet_position - i; // 计算尾巴上第i个LED的位置
         // 亮度随距离头部的距离增加而线性降低（10-i)/10的比例
        uint8_t brightness = 255 * (10 - i) / 10;
        // 设置尾巴LED的颜色（橙黄色系：红=亮度，绿=亮度/2，蓝=0）
        gWs2812bDat[tail_pos].R = brightness / 4;
        gWs2812bDat[tail_pos].G = brightness / 3;
        gWs2812bDat[tail_pos].B = brightness;
    }
    // 发送更新后的颜色数据到WS2812B灯带，刷新显示
    WS2812B_Task();
    // 更新彗星位置，使其向前移动一个LED
    comet_position++;
    // 当彗星移动到灯带末端时，回到起始位置（循环效果）
    if (comet_position >= WS2812B_AMOUNT) {
        comet_position = 0;
    }
}

/**
 * @brief  非阻塞红绿堆积效果更新
 */
void red_to_green_stack_update(void)
{
    // 获取当前系统时间（毫秒级），用于控制动画更新频率
    uint32_t current_time = HAL_GetTick();

    // 速度控制逻辑：根据当前速度等级的延迟时间决定是否更新动画
    // 如果距离上次更新时间小于设定的延迟，不执行更新，直接返回
    if (current_time - effect_last_time < speed_delays[current_speed_level]) {
        return;
    }
    // 更新上次动画更新时间为当前时间
    effect_last_time = current_time;
    
    // 清空所有LED
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 0;
        gWs2812bDat[i].B = 0;
    }

    // 绘制底部绿色堆积效果
    // 从灯带最底部（索引0）开始，向上绘制stack_height个绿色灯珠
    for (uint8_t i = 0; i < stack_height && i < WS2812B_AMOUNT; i++) {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 255;
        gWs2812bDat[i].B = 0;
    }

    // 红色灯珠掉落逻辑（仅当绿色堆积未填满整个灯带时执行）
    if (stack_height < WS2812B_AMOUNT) {
        // 静态变量：记录红色灯珠掉落的步数，确保掉落过程连续平滑
        // 独立于堆积高度，避免高度变化时掉落位置突然跳跃
        static uint8_t drop_counter = 0;

        // 计算当前可掉落的范围（绿色堆积顶部到灯带顶端的距离）
        uint8_t drop_range = WS2812B_AMOUNT - stack_height;

        // 计算红色灯珠当前的掉落位置：从灯带顶端（最大索引）向下移动
        // 通过取模运算实现循环掉落效果
        uint8_t drop_offset = drop_counter % drop_range;
        uint8_t drop_position = WS2812B_AMOUNT - 1 - drop_offset;

        // 在计算出的位置绘制红色灯珠（确保位置在有效范围内）
        if (drop_position >= stack_height && drop_position < WS2812B_AMOUNT) {
            gWs2812bDat[drop_position].R = 255; // 最大红色（纯红色）
            gWs2812bDat[drop_position].G = 0;
            gWs2812bDat[drop_position].B = 0;
        }

        // 掉落结束判断：当红色灯珠落到绿色堆积的顶部时
        if (drop_position == stack_height) {
            stack_height++;    // 绿色堆积高度增加1（红色灯珠"变成"绿色）
            drop_counter = 0;  // 重置掉落计数器，准备下一个红色灯珠掉落
            // 如果绿色堆积填满整个灯带，重置动画从底部开始
            if (stack_height >= WS2812B_AMOUNT) {
                stack_height = 0; // 堆积高度清零
                drop_counter = 0; // 掉落计数器清零
            }
        } else {
            drop_counter++; // 红色灯珠继续向下掉落一步
        }
    }
    // 将更新后的颜色数据发送到WS2812B灯带，刷新显示
    WS2812B_Task();
    // 彩虹相位递增（预留：可能用于未来扩展颜色变化效果）
    rainbow_phase++;
}

/**
 * @brief  非阻塞红色波浪更新
 */
void red_wave_update(void)
{
    // 获取当前系统时间（毫秒级），用于控制动画刷新频率
    uint32_t current_time = HAL_GetTick();

    // 速度控制逻辑：根据当前速度等级的延迟时间决定是否更新动画
    // 如果距离上次更新时间小于设定延迟，不执行更新，直接返回
    if (current_time - effect_last_time < speed_delays[current_speed_level]) {
        return;
    }
    // 更新上次动画刷新时间为当前时间
    effect_last_time = current_time;

    // 波浪位置更新控制：按固定速度（WAVE_SPEED）移动波浪
    if (current_time - last_update_time >= WAVE_SPEED) {
        wave_offset++; // 波浪偏移量+1，使波浪向右移动
        if (wave_offset >= WS2812B_AMOUNT) // 当偏移量超过灯带长度时
        {
            wave_offset = 0; // 重置偏移量，实现循环流动效果
        }
        last_update_time = current_time; // 记录本次位置更新时间
    }
    
    // 清空所有LED
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) { 
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 0;
        gWs2812bDat[i].B = 0;
    }
    
    // 生成纯红色波浪效果
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) {
        // 计算当前灯珠相对于波浪起点的位置（实现波浪循环移动的核心计算）
        // 通过取模运算确保位置始终在有效范围内（0到灯带长度-1）
        int16_t relative_pos = (i - wave_offset + WS2812B_AMOUNT) % WS2812B_AMOUNT;
        // 只在波浪范围内（3到27之间）绘制灯珠，形成一个完整的波浪形状
        if (relative_pos >= 3 && relative_pos < 27) {
            // 计算在波浪中的相对位置（从0开始）
            uint8_t light_pos = relative_pos - 3;
            // 将位置转换为0到π的角度（0到180度），用于生成正弦曲线
            // WAVE_LENGTH是波浪长度，通过它将位置映射到角度
            float angle = (float)light_pos * 3.14159f / (WAVE_LENGTH - 1);
            // 计算亮度系数：正弦函数在0到π区间内从0升到1再降到0，形成波浪形状
            float brightness_factor = sinf(angle);
            // 最低亮度限制：避免波浪尾部过暗导致消失
            if (brightness_factor < 0.1f)
                brightness_factor = 0.1f;
            // 设置当前灯珠的颜色：纯红色，亮度由正弦曲线决定
            gWs2812bDat[i].R = (uint8_t)(255 * brightness_factor);
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        }
    }
    // 将更新后的颜色数据发送到WS2812B灯带，刷新显示当前帧
    WS2812B_Task();
}

/**
 * @brief  非阻塞红绿波浪更新
 */
void red_green_wave_update(void)
{

    // 获取当前系统时间（毫秒级），用于控制动画刷新频率
    uint32_t current_time = HAL_GetTick();

    // 速度控制逻辑：根据当前速度等级的延迟时间决定是否更新动画
    // 如果距离上次更新时间小于设定延迟（speed_delays），不执行更新，直接返回
    // 速度等级越高（current_speed_level越大），延迟越短，波浪刷新越频繁
    if (current_time - effect_last_time < speed_delays[current_speed_level]) {
        return;
    }
    // 更新上次动画刷新时间为当前时间，用于下次延迟判断
    effect_last_time = current_time;

    // 波浪位置更新控制：按固定速度（WAVE_SPEED）移动波浪整体位置
    if (current_time - last_update_time >= WAVE_SPEED) {
        wave_offset++; // 波浪偏移量+1，使波浪向右移动一格
        if (wave_offset >= WS2812B_AMOUNT) {// 当偏移量超过灯带长度时
            wave_offset = 0;                // 重置偏移量，实现波浪循环流动
        }
        last_update_time = current_time; // 记录本次位置更新时间
    }
    
    // 清空所有LED
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 0;
        gWs2812bDat[i].B = 0;
    }

    // 生成红绿波浪效果：遍历每个灯珠，按区域设置颜色
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) {
        // 计算当前灯珠相对于波浪起点的位置（核心：实现波浪随offset移动）
        // 通过取模运算确保位置始终在0~灯带长度-1范围内，实现循环流动
        int16_t relative_pos = (i - wave_offset + WS2812B_AMOUNT) % WS2812B_AMOUNT;

        // 区域1：前6个灯珠（relative_pos 0~5）→ 纯红色区域
        if (relative_pos < 6) {
            // 用正弦函数计算亮度：从0→1→0平滑变化（模拟波浪起伏）
            float brightness = sinf((float)relative_pos * 3.14159f / 5.0f);
            // 3.14159f/5.0f：将0~5的位置映射到0~π的角度（0°~180°）
            if (brightness < 0.2f)
                brightness = 0.2f; // 最低亮度限制为0.2f，避免波浪边缘过暗消失
                                   // 设置纯红色：红色分量随亮度变化，绿色/蓝色为0
            gWs2812bDat[i].R = (uint8_t)(255 * brightness); // 红色亮度由正弦曲线控制
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        } // 区域2：中间6个灯珠（relative_pos 6~11）→ 红色到绿色过渡区域
        else if (relative_pos < 12) {
            // 计算在过渡区域内的相对位置（0~5）
            uint8_t transition_pos = relative_pos - 6;
            // 亮度计算同红色区域：正弦曲线控制明暗起伏
            float brightness = sinf((float)transition_pos * 3.14159f / 5.0f);
            if (brightness < 0.2f) brightness = 0.2f;

            // 过渡因子：0~1之间，控制红绿比例（0=纯红，1=纯绿）
            float transition_factor = (float)transition_pos / 5.0f;
            // 红色随过渡因子减小，绿色随过渡因子增大，实现平滑混合
            gWs2812bDat[i].R = (uint8_t)(255 * (1.0f - transition_factor) * brightness); // 红色减弱
            gWs2812bDat[i].G = (uint8_t)(255 * transition_factor * brightness); // 绿色增强
            gWs2812bDat[i].B = 0;
            // 区域3：后18个灯珠（relative_pos 12~29）→ 纯绿色区域
        } else if (relative_pos < 30) {
            // 计算在绿色区域内的相对位置（0~17）
            uint8_t green_pos = relative_pos - 12;
            // 亮度计算：正弦曲线控制，0~17映射到0~π角度，实现绿色波浪起伏
            float brightness = sinf((float)green_pos * 3.14159f / 17.0f);
            if (brightness < 0.2f) brightness = 0.2f;
            // 设置纯绿色：绿色分量随亮度变化，红色/蓝色为0
            gWs2812bDat[i].R = 0;
            gWs2812bDat[i].G = (uint8_t)(255 * brightness); // 绿色亮度由正弦曲线控制
            gWs2812bDat[i].B = 0;
        }
    }
    
    WS2812B_Task();
}

/**
 * @brief  非阻塞彩虹波浪更新
 */
void rainbow_wave_update(void)
{
    uint32_t current_time = HAL_GetTick();
    
    // 使用当前速度等级的延迟时间
    if (current_time - effect_last_time < speed_delays[current_speed_level]) {
        return;
    }
    effect_last_time = current_time;

    // 波浪位置更新控制：按固定速度（WAVE_SPEED）移动波浪整体位置
    if (current_time - last_update_time >= WAVE_SPEED) {
        wave_offset++; // 波浪偏移量+1，使波浪向右移动一格
        if (wave_offset >= WS2812B_AMOUNT) // 当偏移量超过灯带长度时
        { 
            wave_offset = 0; // 重置偏移量，实现波浪循环流动
        }
        last_update_time = current_time;
    }
    
    // 清空所有LED
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 0;
        gWs2812bDat[i].B = 0;
    }

    // 生成彩虹波浪效果：遍历每个灯珠，按波浪位置设置颜色
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++) {
        // 计算当前灯珠相对于波浪起点的位置（核心：实现波浪随offset移动）
        // 通过取模运算确保位置始终在0~灯带长度-1范围内，实现循环流动
        //灯珠是落后于波浪偏移量的，所以需要加上WS2812B_AMOUNT，避免负数取模异常。
        int16_t relative_pos = (i - wave_offset + WS2812B_AMOUNT) % WS2812B_AMOUNT;
        // 只在波浪长度范围内绘制灯珠（超出范围的灯珠保持熄灭）
        if (relative_pos < WAVE_LENGTH) {
            // 计算波浪亮度：用正弦函数实现从0→1→0的平滑起伏（模拟波浪形态）
            // 3.14159f/(WAVE_LENGTH-1)：将0~波浪长度的位置映射到0~π的角度（0°~180°）
            float brightness = sinf((float)relative_pos * 3.14159f / (WAVE_LENGTH - 1));
            // 最低亮度限制为0.1f，避免波浪边缘过暗导致消失
            if (brightness < 0.1f) brightness = 0.1f;

            // 计算彩虹色相：将波浪长度映射到0~360°的色相范围（红→绿→蓝完整循环）
            // 例如：波浪长度=20，则每个位置对应18°色相变化（360/20=18）
            float hue = (float)relative_pos * 360.0f / WAVE_LENGTH;
            // 定义RGB变量，用于接收颜色转换结果
            uint8_t r, g, b;
            // 将HSV颜色模型转换为RGB模型：
            // hue（色相0-360°）→ 控制红/绿/蓝比例；
            // 1.0f（饱和度）→ 颜色纯度最高；
            // brightness（亮度）→ 由正弦曲线计算的明暗程度
            hsv_to_rgb(hue, 1.0f, brightness, &r, &g, &b);
            
            gWs2812bDat[i].R = r;
            gWs2812bDat[i].G = g;
            gWs2812bDat[i].B = b;
        }
    }
    
    WS2812B_Task();
}
// ==================== 阻塞式灯效函数 ====================
// Red Green Wave灯效函数
void red_green_wave_effect(uint16_t delay_ms)
{
    // 持续运行波浪效果
    for (uint16_t cycle = 0; cycle < 100; cycle++)
    {
        uint32_t current_time = HAL_GetTick(); // 获取当前系统时间（毫秒）

        // 检查是否达到更新波浪的时间间隔
        if (current_time - last_update_time >= WAVE_SPEED)
        {
            wave_offset++; // 波浪偏移量+1（波浪向前移动）
            if (wave_offset >= WS2812B_AMOUNT)
            {
                wave_offset = 0; // 偏移量超过灯珠总数时重置（循环移动）
            }
            last_update_time = current_time; // 更新上次更新时间
        }

        // 清空所有LED
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            gWs2812bDat[i].R = 0;
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        }

        // 生成红绿波浪效果 - 30颗灯珠：6个红色，6个过渡，18个绿色
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            // 在当前波浪位置下，第i颗灯珠相对于波浪起点的位置。
            int16_t relative_pos = (i - wave_offset + WS2812B_AMOUNT) % WS2812B_AMOUNT;
            // 当wave_offset增大时（波浪向前移动），这个差值会减小，相当于灯珠在波浪中的位置 "后退"，造成波浪向前流动的视觉效果。
            //+ WS2812B_AMOUNT：避免负数出现。 当i < wave_offset时，i - wave_offset会是负数，加上灯珠总数后确保结果为正数（不影响最终取模结果，但能避免负数取模的异常）。
            //% WS2812B_AMOUNT：将结果限制在 0 到WS2812B_AMOUNT-1的范围内，实现循环效果。
            if (relative_pos < 6) // 前6个LED：纯红色区域
            {
                // 亮度用正弦函数计算：0~π区间内，亮度从0.2升到1再降到0.2（模拟波浪起伏）
                float brightness = sinf((float)relative_pos * 3.14159f / 5.0f); // 除灯珠数量
                if (brightness < 0.2f)
                    brightness = 0.2f; // 最低亮度限制（避免完全熄灭）
                // 纯红色（绿色和蓝色为0），亮度由brightness控制
                gWs2812bDat[i].R = (uint8_t)(255 * brightness);
                gWs2812bDat[i].G = 0;
                gWs2812bDat[i].B = 0;
            }
            else if (relative_pos < 12)
            {
                // 中间6个LED：红色到绿色的过渡区域
                uint8_t transition_pos = relative_pos - 6;
                float brightness = sinf((float)transition_pos * 3.14159f / 5.0f); // 除灯珠数量
                if (brightness < 0.2f)
                    brightness = 0.2f;
                // 计算逻辑：将 transition_pos（0~5）转换为 0~1 之间的浮点数。作为红、绿两种颜色的 "权重"，
                float transition_factor = (float)transition_pos / 5.0f;
                // 红色分量 = 最大亮度 × (1 - 过渡系数) × 波浪亮度
                gWs2812bDat[i].R = (uint8_t)(255 * (1.0f - transition_factor) * brightness); // 红色占比随系数增大而减小，绿色占比随系数增大而增大。
                // 绿色分量 = 最大亮度 × 过渡系数 × 波浪亮度
                gWs2812bDat[i].G = (uint8_t)(255 * transition_factor * brightness);
                gWs2812bDat[i].B = 0;
            }
            else if (relative_pos < 30) // relative_pos范围：12~29（共18颗）
            {
                // 后18个LED：纯绿色区域
                uint8_t green_pos = relative_pos - 12; // 转换为0~17的局部位置
                // 亮度用正弦函数计算：0~π区间内，亮度从0.2升到1再降到0.2
                float brightness = sinf((float)green_pos * 3.14159f / 17.0f); // 除灯珠数量
                if (brightness < 0.2f)
                    brightness = 0.2f; // 最低亮度限制（避免完全熄灭）

                // 纯绿色（红色和蓝色为0），亮度由brightness控制
                gWs2812bDat[i].R = 0;
                gWs2812bDat[i].G = (uint8_t)(255 * brightness);
                gWs2812bDat[i].B = 0;
            }
            // 其他位置保持黑色（熄灭状态）
        }
        
        // 更新显示并延时
        WS2812B_Task();
        HAL_Delay(delay_ms);
    }
}
/*彩虹效果依赖 HSV 到 RGB 的转换，简单解释该函数的核心逻辑：
HSV 通过 “色相划分 6 个区域” 实现颜色转换，每个区域对应一种主色和相邻色的混合：
hue 0~60°：红色为主，绿色逐渐增加（红→橙→黄）；
hue 60~120°：绿色为主，红色逐渐减少（黄→绿）；
... 以此类推，覆盖 6 个区域后回到红色，形成循环。
函数中通过 fmodf(h/60, 2)-1 计算颜色混合比例，最终得到 RGB 分量。*/
// HSV转RGB函数
void hsv_to_rgb(float h, float s, float v, uint8_t *r, uint8_t *g, uint8_t *b)
{
    float c = v * s;
    float x = c * (1 - fabsf(fmodf(h / 60.0f, 2) - 1));
    float m = v - c;

    float r_temp, g_temp, b_temp;

    if (h >= 0 && h < 60)
    {
        r_temp = c;
        g_temp = x;
        b_temp = 0;
    }
    else if (h >= 60 && h < 120)
    {
        r_temp = x;
        g_temp = c;
        b_temp = 0;
    }
    else if (h >= 120 && h < 180)
    {
        r_temp = 0;
        g_temp = c;
        b_temp = x;
    }
    else if (h >= 180 && h < 240)
    {
        r_temp = 0;
        g_temp = x;
        b_temp = c;
    }
    else if (h >= 240 && h < 300)
    {
        r_temp = x;
        g_temp = 0;
        b_temp = c;
    }
    else
    {
        r_temp = c;
        g_temp = 0;
        b_temp = x;
    }

    *r = (uint8_t)((r_temp + m) * 255);
    *g = (uint8_t)((g_temp + m) * 255);
    *b = (uint8_t)((b_temp + m) * 255);
}

// Rainbow wave灯效函数
void rainbow_wave_effect(uint16_t delay_ms)
{
    // 持续运行波浪效果
    for (uint16_t cycle = 0; cycle < 100; cycle++)
    {
        uint32_t current_time = HAL_GetTick();

        // 检查是否需要更新波浪位置
        if (current_time - last_update_time >= WAVE_SPEED)
        {
            wave_offset++;
            if (wave_offset >= WS2812B_AMOUNT)
            {
                wave_offset = 0;
            }
            last_update_time = current_time;
        }

        // 清空所有LED
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            gWs2812bDat[i].R = 0;
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        }

        // 生成彩虹波浪效果 - 30颗灯珠，6个熄灭，24个亮着
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            // 在当前波浪位置下，第i颗灯珠相对于波浪起点的位置。
            int16_t relative_pos = (i - wave_offset + WS2812B_AMOUNT) % WS2812B_AMOUNT;
            // 当wave_offset增大时（波浪向前移动），这个差值会减小，相当于灯珠在波浪中的位置 "后退"，造成波浪向前流动的视觉效果。
            //+ WS2812B_AMOUNT：避免负数出现。 当i < wave_offset时，i - wave_offset会是负数，加上灯珠总数后确保结果为正数（不影响最终取模结果，但能避免负数取模的异常）。
            //% WS2812B_AMOUNT：将结果限制在 0 到WS2812B_AMOUNT-1的范围内，实现循环效果。

            // 亮灯区域：relative_pos在3~27之间（共24颗灯珠），其余6颗熄灭
            if (relative_pos >= 3 && relative_pos < 27)
            {
                // 计算在亮灯区域内的位置（0-23）
                uint8_t light_pos = relative_pos - 3;

                // 计算亮度，使用正弦波形，中间最亮
                float angle = (float)light_pos * 3.14159f / (WAVE_LENGTH - 1);
                float brightness_factor = sinf(angle);

                // 确保亮度在合理范围内
                if (brightness_factor < 0.1f)
                    brightness_factor = 0.1f;

                // 彩虹的核心是 "颜色随位置渐变" ,计算彩虹色相，根据位置在波浪中的相对位置
                /*HSV 模型中，色相用 0~360 度表示颜色种类（0°= 红、60°= 黄、120°= 绿、180°= 青、240°= 蓝、300°= 紫、360°= 红）。
                这里 light_pos 从 0 到 23 时，hue 从 0° 线性增加到 360°，覆盖完整的彩虹色范围，实现 "红→橙→黄→…→紫" 的渐变。*/
                float hue = (float)light_pos * 360.0f / (WAVE_LENGTH - 1);
                float saturation = 1.0f;         // 饱和度最大
                float value = brightness_factor; // 亮度根据波浪形状变化

                // 转换HSV到RGB
                uint8_t r, g, b;
                /*将 HSV 颜色模型的三个参数（色相、饱和度、明度）转换为 LED 实际需要的 RGB 值（红、绿、蓝分量）。 */
                hsv_to_rgb(hue, saturation, value, &r, &g, &b);

                // 设置彩虹色
                gWs2812bDat[i].R = r;
                gWs2812bDat[i].G = g;
                gWs2812bDat[i].B = b;
            }
            // 其他6个位置保持黑色（熄灭状态）
        }
        
        // 更新显示并延时
        WS2812B_Task();
        HAL_Delay(delay_ms);
    }
}

/**
 * @brief  统一颜色渐变效果
 * @param  steps: 每个颜色的中间过渡色
 * @param  delay_ms: 每步之间的延迟时间（毫秒）
 */
void uniform_gradient(uint8_t steps, uint16_t delay_ms)
{
    //定义一个二维数组，7行3列
    uint8_t colors[][3] = {
        {255, 0, 0},    // 红色
        {0, 255, 0},    // 绿色
        {0, 0, 255},    // 蓝色
        {255, 255, 0},  // 黄色
        {0, 255, 255},  // 青色
        {255, 0, 255},  // 紫色
        {255, 255, 255} // 白色
    };
                                                //第一行
    uint8_t num_colors = sizeof(colors) / sizeof(colors[0]); // 计算colors颜色数组有多少行，即有多少个颜色点，7行

    for (uint8_t color_idx = 0; color_idx < num_colors; color_idx++) // 循环遍历所有关键颜色，每次处理从当前颜色到下一个颜色的渐变
    {                               //1-7
        uint8_t next_color_idx = (color_idx + 1) % num_colors; // 使用取模运算实现颜色循环，最后一个颜色的下一个颜色是第一个颜色（0到6）,第一次1。

        // 计算颜色渐变步长,分别计算红、绿、蓝三个通道从当前颜色到下一个颜色的每步变化量
        float r_step = (float)(colors[next_color_idx][0] - colors[color_idx][0]) / steps; // 红色步长(0-255)/30 ≈ -85
        float g_step = (float)(colors[next_color_idx][1] - colors[color_idx][1]) / steps; // 绿色步长(255-0)/30 = 85
        float b_step = (float)(colors[next_color_idx][2] - colors[color_idx][2]) / steps; // 蓝色步长(0-0)/30 = 0

        //  设置个传入函数步长的循环
        for (uint8_t step = 0; step < steps; step++)
        {
            uint8_t r = (uint8_t)(colors[color_idx][0] + r_step * step); //(255+(-85)0, 0+850, 0) → (255,0,0)（红色）(255+(-85)1, 0+851, 0) → (170,85,0)（橙红色）(255+(-85)2, 0+852, 0) → (85,170,0)（黄绿色
            uint8_t g = (uint8_t)(colors[color_idx][1] + g_step * step);
            uint8_t b = (uint8_t)(colors[color_idx][2] + b_step * step);

            // 更新所有LED为相同的颜色
            for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
            {
                gWs2812bDat[i].R = r;
                gWs2812bDat[i].G = g;
                gWs2812bDat[i].B = b;
            }

            WS2812B_Task();
            HAL_Delay(delay_ms);
        }
    }
}

/**
 * @brief  彗星效果
 * @param  tail_length: 彗星尾巴长度
 * @param  brightness: 彗星头部亮度（0-255）
 * @param  delay_ms: 移动延迟时间（毫秒）
 */
void comet_effect(uint8_t tail_length, uint8_t brightness, uint16_t delay_ms)
{
    uint8_t colors[][3] = {
        {255, 0, 0},    // 红色
        {0, 255, 0},    // 绿色
        {0, 0, 255},    // 蓝色
        {255, 255, 0},  // 黄色
        {0, 255, 255},  // 青色
        {255, 0, 255},  // 紫色
        {255, 255, 255} // 白色
    };                                      // 第一行
    uint8_t num_colors = sizeof(colors) / sizeof(colors[0]); // 计算colors颜色数组有多少行，即有多少个颜色点，7行

    for (uint8_t color_idx = 0; color_idx < num_colors; color_idx++) // 循环遍历 7 种颜色，每种颜色都会生成一次完整的彗星效果
    {
        // 清除所有LED
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            gWs2812bDat[i].R = 0;
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        }

        // 彗星从左到右移动head表示彗星头部的位置
        //从 - tail_length开始（初始时彗星完全在灯带左侧外面），逐渐移动到灯带最右侧（WS2812B_AMOUNT - 1）
         for (int16_t head = -tail_length; head < WS2812B_AMOUNT; head++)
        {
            // 更新彗星头部和尾部
            // 计算并设置彗星头部到尾部的每个 LED 的颜色和亮度：
            /*首先i从head=-10，到head-tail_length=-20结束，但i >= 0不成立，故不执行任何 LED 设置。
            */
            for (int16_t i = head; i > head - tail_length && i >= 0; i--)
            {
                //当i=head等于0，头部进入灯带第 0 个 LED
                 if (i < WS2812B_AMOUNT)
                {
                    // 计算尾部渐变亮度
                    // fade_ratio = (0-0)/10 = 0 → 亮度led_brightness=255*(1-0)=255（最亮）。
                    /*  尾部更新循环：i从1到1-3=-2，有效i=1、0：
                        i=1（头部）：fade_ratio=0 → 亮度 255 → RGB (255,0,0)。
                        i=0（尾部）：fade_ratio=(1-0)/10=0.1 → 亮度255*(0.9)=230 → RGB (230,0,0)（稍暗红色）。*/
                    float fade_ratio = (float)(head - i) / tail_length;
                    uint8_t led_brightness = (uint8_t)(brightness * (1.0f - fade_ratio));
                    /*
                    头部（i=head）：fade_ratio=0 → 亮度为brightness（最亮）
                    尾部（i=head-tail_length+1）：fade_ratio≈1 → 亮度接近 0（最暗）
                    中间部分：亮度从头部到尾部逐渐降低*/
                    /*根据计算出的亮度，调整当前颜色的 RGB 值（亮度越低，颜色越暗）*/
                    gWs2812bDat[i].R = (uint8_t)((float)colors[color_idx][0] * led_brightness / 255);//设置为是
                    gWs2812bDat[i].G = (uint8_t)((float)colors[color_idx][1] * led_brightness / 255);
                    gWs2812bDat[i].B = (uint8_t)((float)colors[color_idx][2] * led_brightness / 255);
                }
            }

            // 清除彗星尾部
            /*当彗星移动时，将超出尾部长度的 LED 熄灭，避免彗星拖出多余的残影*/
            /*当head=10时，head-tail_length=0（即 LED0）LED0 已经超出尾部范围，需要被清除*/
            if (head - tail_length >= 0 && head - tail_length < WS2812B_AMOUNT)
            {
                gWs2812bDat[head - tail_length].R = 0;
                gWs2812bDat[head - tail_length].G = 0;
                gWs2812bDat[head - tail_length].B = 0;
            }

            WS2812B_Task();
            HAL_Delay(delay_ms);
        }
    }
}

// Red to Green Stack效果：红色LED从顶部掉落，落下瞬间变绿色并累积
void WS2812B_red_to_green_stack(uint16_t delay_ms)
{
    uint8_t stack_step = 0;  // 记录当前 LED 的掉落步骤（控制红色 LED 从顶部向下移动的进度）
    uint8_t green_count = 0; // 记录已堆叠变绿的 LED 数量

    // 完整的动画循环，直到所有LED都变绿
    while (green_count < WS2812B_AMOUNT)
    {
        // 清除所有LED
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            gWs2812bDat[i].R = 0;
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        }

        // 显示已经落下并变绿的LED（从底部开始累积）首先是不显示绿色
        for (uint8_t i = 0; i < green_count; i++)
        {
            gWs2812bDat[i].R = 0;
            gWs2812bDat[i].G = 255; // 绿色
            gWs2812bDat[i].B = 0;
        }

        // 计算红色灯珠掉落的位置（从顶部掉落到绿色堆积的顶部）
        uint8_t falling_pos = WS2812B_AMOUNT - 1 - stack_step;

        // 如果掉落位置还在绿色堆积之上，显示红色掉落LED
        if (falling_pos >= green_count)
        {
            gWs2812bDat[falling_pos].R = 255; // 掉落中的红色LED
            gWs2812bDat[falling_pos].G = 0;
            gWs2812bDat[falling_pos].B = 0;
        }

        // 发送数据到LED硬件
        WS2812B_Task();
        HAL_Delay(delay_ms);

        stack_step++;

        // 当红色LED落到绿色堆积顶部时，变成绿色并增加绿色计数
        if (stack_step > (WS2812B_AMOUNT - 1 - green_count))
        {
            green_count++;  // 增加绿色LED数量
            stack_step = 0; // 重置掉落步骤，准备下一个LED掉落
        }
    }

    // 显示最终的全绿色状态
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        gWs2812bDat[i].R = 0;
        gWs2812bDat[i].G = 255; // 绿色
        gWs2812bDat[i].B = 0;
    }
    WS2812B_Task();           // 发送数据到LED硬件

}

/**
 * @brief  彩虹渐变效果
 * @param  steps: 每个颜色的中间过渡色
 * @param  delay_ms: 每步之间的延迟时间（毫秒）
 */
void rainbow_gradient(uint8_t steps, uint16_t delay_ms)
{
    for (uint8_t phase = 0; phase < 255; phase += 5)
    {
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            // 计算每个LED的色相偏移
            uint8_t hue = (phase + (i * 255 / WS2812B_AMOUNT)) % 255;

            // 简化的HSV到RGB转换（只使用色相，饱和度和亮度固定）
            uint8_t r, g, b;
            if (hue < 85)
            {
                r = 255 - hue * 3;
                g = hue * 3;
                b = 0;
            }
            else if (hue < 170)
            {
                hue -= 85;
                r = 0;
                g = 255 - hue * 3;
                b = hue * 3;
            }
            else
            {
                hue -= 170;
                r = hue * 3;
                g = 0;
                b = 255 - hue * 3;
            }

            gWs2812bDat[i].R = r;
            gWs2812bDat[i].G = g;
            gWs2812bDat[i].B = b;
        }

        WS2812B_Task();
        HAL_Delay(delay_ms);
    }
}
// Red Wave纯红色波浪效果
void red_wave_effect(uint16_t delay_ms)
{
    // 持续运行波浪效果
    for (uint16_t cycle = 0; cycle < 100; cycle++)
    {
        uint32_t current_time = HAL_GetTick();

        // 检查是否需要更新波浪位置
        if (current_time - last_update_time >= WAVE_SPEED)
        {
            wave_offset++;
            if (wave_offset >= WS2812B_AMOUNT)
            {
                wave_offset = 0;
            }
            last_update_time = current_time;
        }

        // 清空所有LED
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            gWs2812bDat[i].R = 0;
            gWs2812bDat[i].G = 0;
            gWs2812bDat[i].B = 0;
        }

        // 生成纯红色波浪效果 - 30颗灯珠，6个熄灭，24个亮着
        for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
        {
            // 在当前波浪位置下，第i颗灯珠相对于波浪起点的位置。
            int16_t relative_pos = (i - wave_offset + WS2812B_AMOUNT) % WS2812B_AMOUNT;

            // 波浪区域：24个亮灯，6个熄灭
            // 亮灯区域从位置3到位置26（24个LED）
            if (relative_pos >= 3 && relative_pos < 27)
            {
                // 计算在亮灯区域内的位置（0-23）
                uint8_t light_pos = relative_pos - 3;

                // 计算亮度，使用正弦波形，中间最亮
                float angle = (float)light_pos * 3.14159f / (WAVE_LENGTH - 1);
                float brightness_factor = sinf(angle);

                // 确保亮度在合理范围内
                if (brightness_factor < 0.1f)
                    brightness_factor = 0.1f;

                // 设置纯红色
                gWs2812bDat[i].R = (uint8_t)(255 * brightness_factor);
                gWs2812bDat[i].G = 0;
                gWs2812bDat[i].B = 0;
            }
            // 其他6个位置保持黑色（熄灭状态）
        }

        // 更新显示并延时
        WS2812B_Task();
        HAL_Delay(delay_ms);
    }
}
/**
 * @brief  通过渐变方式更新LED颜色（线性插值）
 * @param  target_colors: 目标颜色数组
 * @param  steps: 渐变步数
 * @param  delay_ms: 每步之间的延迟时间（毫秒）
 */
void ws2812_gradient(tWs2812bCache_TypeDef target_colors[], uint8_t steps, uint16_t delay_ms)
{
    static uint8_t start_r[WS2812B_AMOUNT], start_g[WS2812B_AMOUNT], start_b[WS2812B_AMOUNT];
    static float r_step[WS2812B_AMOUNT], g_step[WS2812B_AMOUNT], b_step[WS2812B_AMOUNT];

    // 保存当前颜色作为起始颜色，并计算每步的渐变步长
    for (uint8_t i = 0; i < WS2812B_AMOUNT; i++)
    {
        start_r[i] = gWs2812bDat[i].R;
        start_g[i] = gWs2812bDat[i].G;
        start_b[i] = gWs2812bDat[i].B;

        r_step[i] = (float)(target_colors[i].R - start_r[i]) / steps;
        g_step[i] = (float)(target_colors[i].G - start_g[i]) / steps;
        b_step[i] = (float)(target_colors[i].B - start_b[i]) / steps;
    }

    // 逐步渐变
    for (uint8_t step = 1; step <= steps; step++)
    {
        for (uint8_t led_id = 0; led_id < WS2812B_AMOUNT; led_id++)
        {
            // 计算当前步的颜色
            uint8_t r = (uint8_t)(start_r[led_id] + r_step[led_id] * step);
            uint8_t g = (uint8_t)(start_g[led_id] + g_step[led_id] * step);
            uint8_t b = (uint8_t)(start_b[led_id] + b_step[led_id] * step);

            gWs2812bDat[led_id].R = r;
            gWs2812bDat[led_id].G = g;
            gWs2812bDat[led_id].B = b;
        }

        WS2812B_Task();
        HAL_Delay(delay_ms);
    }
}
